package com.waitingsnow.modules.shell.view.video
{
import com.waitingsnow.core.debug.Logger;
import com.waitingsnow.core.model.config.AppConfig;
import com.waitingsnow.core.service.NetConnectionService;
import com.waitingsnow.core.util.ds.ExternalUtil;
import com.waitingsnow.modules.shell.model.vo.VideoSetVO;
import com.waitingsnow.modules.shell.view.video.events.PublishVideoEvent;

import flash.events.Event;
import flash.events.NetStatusEvent;
import flash.events.StatusEvent;
import flash.media.Camera;
import flash.media.Microphone;
import flash.media.Video;
import flash.net.NetStream;
import flash.utils.clearInterval;
import flash.utils.getDefinitionByName;
import flash.utils.setInterval;
import flash.utils.setTimeout;

/**
 * 
 * @author waitingsnow
 * $Id: PublishVideo.as 2 2012-05-17 10:10:03Z cgslendy@gmail.com $
 */
public class PublishVideo extends Video
{
	//==========================================================================
	//  Class variables
	//==========================================================================
	static private const CAMERA_WIDTH:int = 592;
	
	//==========================================================================
	//  Constructor
	//==========================================================================
	/**
	 * Constructs a new <code>PublishVideo</code> instance.
	 * 
	 */
	public function PublishVideo(width:int=320, height:int=240)
	{
		super(width, height);
		smoothing = true;
		deblocking = 2;
	}
	
	//==========================================================================
	//  Variables
	//==========================================================================
	private var _camera:Camera;
	private var _micro:Microphone;
	private var _radio:Number;
	
	private var connService:NetConnectionService;
	private var publishNs:NetStream;
	private var reConnectIntervalID:int;
	private var publishType:String = "live";
	private var _streamName:String;
	private var startFlag:Boolean;
	
	/**
	 * 检测摄像头计时器次数
	 */	
	private var checkCameraTime:int = 0;
	
	/**
	 * 检测摄像头状态计时器ID
	 */	
	private var intervalID:int;
	
	//==========================================================================
	//  Properties
	//==========================================================================
	private var _videoSetVO:VideoSetVO;
	public function set videoSetVO(value:VideoSetVO):void
	{
		_videoSetVO = value;
	}
	
	private var _microLevel:Number;
	public function get microLevel():Number
	{
		_micro && (_microLevel = _micro.activityLevel);
		return _microLevel;
	}
	
	//==========================================================================
	//  Methods
	//==========================================================================
	public function startPublish(streamName:String):void
	{
		_streamName = streamName;
		initCamera();
		initMicro();
		if (connService && connService.connected)
		{
			initNetstream();
		}
		else
		{
			initConn();
		}
	}
	
	public function setSize(width:int, height:int):void
	{
		this.width = width;
		this.height = height;
	}
	
	public function dispose():void
	{
		parent && parent.removeChild(this);
		publishNs && publishNs.close();
		connService && connService.dispose();
	}
	
	private function initCamera():void
	{
		_radio = _videoSetVO.cameraRadioIndex ? 3/4 : 9/16;
		_camera = Camera.getCamera(_videoSetVO.cameraIndex);
		if (_camera)
		{
			_camera.setMode(CAMERA_WIDTH, int(CAMERA_WIDTH*_radio), _videoSetVO.cameraFrame);
			_camera.setKeyFrameInterval(_videoSetVO.cameraFrame);
			_camera.setQuality(0, _videoSetVO.cameraQuality);
			_camera.addEventListener(StatusEvent.STATUS, camera_statusHandler);
		}
		else
		{
			dispatchEvent(new PublishVideoEvent(PublishVideoEvent.SHOW_CAMERA_BUSY));
		}
		attachCamera(_camera);
	}
	
	/**
	 * 检测摄像头状态
	 */
	private function checkCamBusy():void
	{
		var callback:Function;
		checkCameraTime = 0;
		clearInterval(intervalID);
		callback = function():void
		{
			checkCameraTime++;
			if(_camera.currentFPS > 0)
			{
				clearInterval(intervalID);
			}
			else if(checkCameraTime > 20)
			{
				clearInterval(intervalID);
				dispatchEvent(new PublishVideoEvent(PublishVideoEvent.SHOW_CAMERA_BUSY));
				Logger.log("您的设备不可用或被占用");
			}
		}
		intervalID = setInterval(callback, 100);
	}
	
	/**
	 * 检测摄像头状态
	 */
	private function checkCameraStatus():void
	{
		if (_camera)
		{
			if (!_camera.muted)
			{
				//允许之后进行带宽检测
				checkCamBusy();
			}
			else
			{
				dispatchEvent(new PublishVideoEvent(PublishVideoEvent.SHOW_CAMERA_REFUSE));
			}
		}
	}
	
	private function initMicro():void
	{
		_micro = Microphone.getMicrophone(_videoSetVO.microIndex);
		if (_micro)
		{
			_micro.setLoopBack(false);
			_micro.gain = _videoSetVO.microGain;
			_micro.rate = _videoSetVO.microQuality;
		}
	}
	
	private function initConn():void
	{
		if (!connService)
		{
			connService = new NetConnectionService();
			connService.addEventListener(Event.CONNECT, connectHandler);
			connService.addEventListener(Event.CLOSE, connCloseHandler);
		}
		connService.startConn(AppConfig.VIDEO_UPLOAD_URL, AppConfig.VIDEO_CONN_TOKEN);
	}
	
	private function initNetstream():void
	{
		removeNs();
		publishNs = new NetStream(connService.connection);
		publishNs.client = {}; 
		publishNs.addEventListener(NetStatusEvent.NET_STATUS, inputNetStatusHandler);
		if (publishNs.hasOwnProperty('videoStreamSettings'))
		{
			Logger.log("use h264");
			var h264Class:Class = 
				getDefinitionByName("flash.media::H264VideoStreamSettings") as Class;
			var h264:Object = new h264Class();
			h264["setProfileLevel"]("baseline", "3");
			publishNs["videoStreamSettings"] = h264;
		}
		publishNs.attachAudio(_micro);
		publishNs.attachCamera(_camera);
		publishNs.publish(_streamName, publishType);
	}
	
	private function removeNs():void
	{
		if (publishNs)
		{
			publishNs.removeEventListener(NetStatusEvent.NET_STATUS, inputNetStatusHandler);
			publishNs.close();
		}
	}
	
	//==========================================================================
	//  Event Handlers
	//==========================================================================
	private function connectHandler(event:Event):void
	{
		initNetstream();
	}
	
	private function connCloseHandler(event:Event):void
	{
		Logger.log("开始断线重连...");
		reConnectIntervalID = setTimeout(initConn, 1000);
		if (startFlag)
		{
			startFlag = false;
			ExternalUtil.call(AppConfig.END_POD_CAST_TO_JS);
		}
	}
	
	private function inputNetStatusHandler(event:NetStatusEvent):void
	{
		Logger.log("inputNs.info: " + event.info.code);
		var result:String = event.info.code;
		if (result == "NetStream.Publish.Start")
		{
			startFlag = true;
			ExternalUtil.call(AppConfig.START_POD_CAST_TO_JS);
		}
	}
	
	/**
	 * 用户选择摄像头隐私设置后触发
	 * @param event
	 * 
	 */    
	private function camera_statusHandler(event:StatusEvent):void
	{
		_camera.removeEventListener(StatusEvent.STATUS, camera_statusHandler);
		checkCameraStatus();
	}
}
}